// $Id: IEnumerable.java 89 2012-11-26 07:16:54Z marcel.kloubert $

/*****************************************************************************
 *                                                                           *
 *   Licensed to the Apache Software Foundation (ASF) under one              *
 *   or more contributor license agreements.  See the NOTICE file            *
 *   distributed with this work for additional information                   *
 *   regarding copyright ownership.  The ASF licenses this file              *
 *   to you under the Apache License, Version 2.0 (the                       *
 *   "License"); you may not use this file except in compliance              *
 *   with the License.  You may obtain a copy of the License at              *
 *                                                                           *
 *       http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                           *
 *   Unless required by applicable law or agreed to in writing,              *
 *   software distributed under the License is distributed on an             *
 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY                  *
 *   KIND, either express or implied.  See the License for the               *
 *   specific language governing permissions and limitations                 *
 *   under the License.                                                      *
 *                                                                           *
 *****************************************************************************/


package net.metalvz.linq;

import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * Describes a sequence.
 * 
 * @author Marcel Joachim Kloubert <marcel.kloubert@gmx.net>
 * 
 * @param <T> Type of the items.
 * 
 * @see http://msdn.microsoft.com/en-us/library/9eekhta0.aspx
 */
public interface IEnumerable<T> extends Iterable<T> {
	/**
	 * Checks if all items of that sequence
	 * match a set of criteria.
	 *  
	 * @param predicate The predicate to use.
	 * 
	 * @throws NullPointerException Predicate is (null).
	 *  
	 * @return All items match the criteria (true) or not (false).
	 */
	boolean all(Predicate<T> predicate);
	
	/**
	 * Checks if that sequence contains at least one item.
	 *  
	 * @return Contains at least one item (true) or not (false).
	 */
	boolean any();
	
	/**
	 * Checks if that sequence contains at least one item
	 * that matches.
	 * 
	 * @param predicate The predicate to use.
	 * 
	 * @throws NullPointerException Predicate is (null).
	 * 
	 * @return Contains at least one item (true) or not (false).
	 */
	boolean any(Predicate<T> predicate);
	
	/**
	 * Casts all elements of that sequence to a specific target type.
	 * 
	 * @param <U> The target type.
	 * 
	 * @return The list with casted items.
	 */
	<U> IEnumerable<U> cast();
	
	/**
	 * Checks if an item is part of that sequence.
	 * 
	 * @param itemToCheck The item to check.
	 * 
	 * @return Is part (true) or not (false).
	 */
	boolean contains(T itemToCheck);
	
	/**
	 * Counts the elements of that sequence.
	 * 
	 * @return the number of elements.
	 */
	int count();
	
	/**
	 * Returns the first element of that sequence.
	 * 
	 * @return The first element of that sequence.
	 * 
	 * @throws EnumerableException Sequence does NOT contain elements.
	 */
	T first();
	
	/**
	 * Returns the first element of that sequence
	 * that matches a set of criteria.
	 * 
	 * @param predicate The predicate to find the first element.
	 * 
	 * @return The first element of that sequence.
	 * 
	 * @throws EnumerableException Sequence does NOT contain elements.
	 * @throws NullPointerException Predicate is (null).
	 */
	T first(Predicate<T> predicate);
	
	/**
	 * Tries to returns the first element of that sequence.
	 * 
	 * @return The first element of that sequence or (null) if not found.
	 */
	T firstOrDefault();
	
	/**
	 * Tries to returns the first element of that sequence
	 * that matches a set of criteria.
	 * 
	 * @param predicate The predicate to find the first element.
	 * 
	 * @return The first element of that sequence or (null) if not found.
	 * 
	 * @throws NullPointerException Predicate is (null).
	 */
	T firstOrDefault(Predicate<T> predicate);
	
	/**
	 * Groups the items of that sequence.
	 * 
	 * @param keySelector The function that produces the keys.
	 * 
	 * @return The list of grouped items.
	 * 
	 * @throws NullPointerException Function is (null).
	 */
	<K> IEnumerable<IGrouping<K, T>> groupBy(Func1<T, K> keySelector);
	
	/**
	 * Returns the zero-based index of an object inside that sequence.
	 * 
	 * @param itemToSearch The item to search for.
	 * 
	 * @return The zero-based index or -1 if NOT found.
	 */
	int indexOf(T itemToSearch);
	
	/**
	 * Returns the last element of that sequence.
	 * 
	 * @return The last element of that sequence.
	 * 
	 * @throws EnumerableException Sequence does NOT contain elements.
	 */
	T last();
	
	/**
	 * Returns the last element of that sequence
	 * that matches a set of criteria.
	 * 
	 * @param predicate The predicate to find the last element.
	 * 
	 * @return The last element of that sequence.
	 * 
	 * @throws NullPointerException Predicate is (null).
	 * @throws EnumerableException Sequence does NOT contain elements.
	 */
	T last(Predicate<T> predicate);
	
	/**
	 * Tries to returns the last element of that sequence.
	 * 
	 * @return The first last of that sequence or (null) if not found.
	 */
	T lastOrDefault();
	
	/**
	 * Tries to returns the last element of that sequence
	 * that matches a set of criteria.
	 * 
	 * @param predicate The predicate to find the last element.
	 * 
	 * @return The last element of that sequence or (null) if not found.
	 * 
	 * @throws NullPointerException Predicate is (null).
	 */
	T lastOrDefault(Predicate<T> predicate);
	
	/**
	 * Sorts the items of that sequence.
	 * 
	 * @param comparator The comparator to use.
	 * 
	 * @return The sorted sequence.
	 * 
	 * @throws NullPointerException Comparator is (null).
	 */
	IEnumerable<T> orderBy(Comparator<T> comparator);
	
	/**
	 * Sorts the items of that sequence (descending).
	 * 
	 * @param comparator The comparator to use.
	 * 
	 * @return The sorted sequence.
	 * 
	 * @throws NullPointerException Comparator is (null).
	 */
	IEnumerable<T> orderByDescending(Comparator<T> comparator);
	
	/**
	 * Converts the items of that sequence to a new sequence.
	 * 
	 * @param selector The selector function.
	 * 
	 * @return The new sequence.
	 * 
	 * @throws NullPointerException Function is (null).
	 */
	<U> IEnumerable<U> select(Func1<T, U> selector);
	
	/**
	 * Converts the items of that sequence to a new (merged) sequence.
	 * 
	 * @param selector The selector function.
	 * 
	 * @return The new sequence.
	 * 
	 * @throws NullPointerException Function is (null).
	 */
	<U> IEnumerable<U> selectMany(Func1<T, Iterable<U>> selector);
	
	/**
	 * Converts the items of that sequence to a new (merged) sequence.
	 * 
	 * @param selector The selector function.
	 * 
	 * @return The new sequence.
	 * 
	 * @throws NullPointerException Function is (null).
	 */
	<U> IEnumerable<U> selectManyArray(Func1<T, U[]> selector);
	
	/**
	 * Returns the last element of that sequence.
	 * 
	 * @return The last element of that sequence.
	 * 
	 * @throws EnumerableException Sequence does NOT contain elements.
	 */
	T single();
	
	/**
	 * Returns the last element of that sequence
	 * that matches a set of criteria.
	 * 
	 * @param predicate The predicate to find the last element.
	 * 
	 * @return The last element of that sequence.
	 * 
	 * @throws EnumerableException Sequence does NOT contain elements.
	 * @throws NullPointerException Predicate is (null).
	 */
	T single(Predicate<T> predicate);
	
	/**
	 * Tries to returns the last element of that sequence.
	 * 
	 * @return The first last of that sequence or (null) if not found.
	 * 
	 * @throws EnumerableException Sequence does NOT contain elements
	 *                             or no item was found.
	 */
	T singleOrDefault();
	
	/**
	 * Tries to returns the last element of that sequence
	 * that matches a set of criteria.
	 * 
	 * @param predicate The predicate to find the last element.
	 * 
	 * @return The last element of that sequence or (null) if not found.
	 * 
	 * @throws EnumerableException Sequence does NOT contain elements
	 *                             or no item was found.
	 * @throws NullPointerException Predicate is (null).
	 */
	T singleOrDefault(Predicate<T> predicate);
	
	/**
	 * Skips a number of items of that sequence.
	 * 
	 * @param count The number of items to skip.
	 * 
	 * @return The new sequence.
	 */
	IEnumerable<T> skip(int count);
	
	/**
	 * Skips items while a set of criteria match.
	 * 
	 * @param predicate The predicate.
	 * 
	 * @return The new sequence.
	 * 
	 * @throws NullPointerException Predicate is (null).
	 */
	IEnumerable<T> skipWhile(Predicate<T> predicate);
	
	/**
	 * Takes a number of items of that sequence.
	 * 
	 * @param count The number of items to take.
	 * 
	 * @return The new sequence.
	 */
	IEnumerable<T> take(int count);
	
	/**
	 * Takes items while a set of criteria match.
	 * 
	 * @param predicate The predicate.
	 * 
	 * @return The new sequence.
	 * 
	 * @throws NullPointerException Predicate is (null).
	 */
	IEnumerable<T> takeWhile(Predicate<T> predicate);
	
	/**
	 * Returns that sequence as array.
	 * 
	 * @param dummyArray The dummy array (should be empty) to defined the
	 *                   type of the result array while it is created.
	 * 
	 * @return The sequence as array.
	 * 
	 * @throws NullPointerException Array is (null).
	 */
	T[] toArray(T[] dummyArray);
	
	/**
	 * Returns that sequence as list.
	 * 
	 * @return The sequence as list.
	 */
	List<T> toList();

	/**
	 * Returns that sequence to a map. 
	 * 
	 * @param keySelector The function that produces the keys for each item.
	 * 
	 * @return The sequence as map.
	 * 
	 * @throws EnumerableException Duplicate key was produced by selector.
	 * @throws NullPointerException Function is (null).
	 */
	<K> Map<K, T> toMap(Func1<T, K> keySelector);
	
	/**
	 * Filters the items of that sequence.
	 * 
	 * @param filter The filter.
	 * 
	 * @return The filtered elements.
	 * 
	 * @throws NullPointerException Filter is (null).
	 */
	IEnumerable<T> where(Predicate<T> filter);
}
